Conversation
- Replace .html() with .text() for plain-text values (numeric counts, date strings, carrier scores) in feed.js, order.js, order_setting.js - Add lengowIsValidUrl() helper to validate URLs before window.open() and window.location.href assignments in feed.js, order.js, main_setting.js - Keep .html() for trusted backend-rendered HTML fragments Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR upgrades the module for PrestaShop 8+ up to 9.x by migrating admin pages to Symfony controllers with Twig templates, replacing legacy webservice endpoints with FrontControllers, and tightening security/typing across the codebase.
Changes:
- Migrates multiple admin pages from Smarty to Twig and introduces Symfony admin controllers + DI wiring.
- Replaces
webservice/*.phpendpoints with module FrontControllers and adds route mappings for backward compatibility. - Improves security (URL validation, safer DOM writes) and adds stricter typing + PHPStan configuration.
Reviewed changes
Copilot reviewed 133 out of 186 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| views/templates/admin/lengow_main_setting/view.html.twig | Adds Twig version of Main Settings admin view |
| views/templates/admin/lengow_main_setting/layout.tpl | Removes legacy Smarty layout wrapper |
| views/templates/admin/lengow_main_setting/helpers/view/view.tpl | Removes legacy Smarty view |
| views/templates/admin/lengow_legals/view.html.twig | Adds Twig version of Legals admin view |
| views/templates/admin/lengow_legals/layout.tpl | Removes legacy Smarty layout wrapper |
| views/templates/admin/lengow_legals/helpers/view/view.tpl | Removes legacy Smarty view |
| views/templates/admin/lengow_home/view.html.twig | Adds Twig version of Home admin view |
| views/templates/admin/lengow_home/layout.tpl | Removes legacy Smarty layout wrapper |
| views/templates/admin/lengow_home/helpers/view/view.tpl | Removes legacy Smarty view |
| views/templates/admin/lengow_home/helpers/view/connection_home.tpl | Removes legacy Smarty partial |
| views/templates/admin/lengow_home/helpers/view/connection_home.html.twig | Adds Twig partial for connection home |
| views/templates/admin/lengow_home/helpers/view/connection_cms_result.tpl | Removes legacy Smarty partial |
| views/templates/admin/lengow_home/helpers/view/connection_cms_result.html.twig | Adds Twig partial for CMS connection result |
| views/templates/admin/lengow_home/helpers/view/connection_cms.tpl | Removes legacy Smarty partial |
| views/templates/admin/lengow_home/helpers/view/connection_cms.html.twig | Adds Twig partial for CMS credentials form |
| views/templates/admin/lengow_home/helpers/view/connection_catalog_failed.tpl | Removes legacy Smarty partial |
| views/templates/admin/lengow_home/helpers/view/connection_catalog_failed.html.twig | Adds Twig partial for catalog-link failure |
| views/templates/admin/lengow_home/helpers/view/connection_catalog.tpl | Removes legacy Smarty partial |
| views/templates/admin/lengow_home/helpers/view/connection_catalog.html.twig | Adds Twig partial for catalog linking |
| views/templates/admin/lengow_help/view.html.twig | Adds Twig version of Help admin view |
| views/templates/admin/lengow_help/layout.tpl | Removes legacy Smarty layout wrapper |
| views/templates/admin/lengow_help/helpers/view/view.tpl | Removes legacy Smarty view |
| views/templates/admin/lengow_feed/view.html.twig | Adds Twig version of Feed admin view |
| views/templates/admin/lengow_feed/layout.tpl | Removes legacy Smarty layout wrapper |
| views/templates/admin/lengow_feed/helpers/view/view.tpl | Removes legacy Smarty view |
| views/templates/admin/lengow_dashboard/view.html.twig | Adds Twig version of Dashboard admin view |
| views/templates/admin/lengow_dashboard/layout.tpl | Removes legacy Smarty layout wrapper |
| views/templates/admin/lengow_dashboard/helpers/view/view.tpl | Removes legacy Smarty view |
| views/templates/admin/lengow_dashboard/helpers/view/status.tpl | Removes legacy Smarty status view |
| views/templates/admin/lengow_dashboard/helpers/view/status.html.twig | Adds Twig status view |
| views/templates/admin/lengow_dashboard/helpers/view/dashboard.tpl | Removes legacy Smarty dashboard view |
| views/templates/admin/lengow_dashboard/helpers/view/dashboard.html.twig | Adds Twig dashboard view |
| views/templates/admin/header_order.tpl | Removes legacy Smarty order header |
| views/templates/admin/header.tpl | Removes legacy Smarty header (JS/CSS + menu) |
| views/templates/admin/footer.tpl | Removes legacy Smarty footer (incl. upgrade modal) |
| views/js/lengow/order_setting.js | Hardens DOM write by using .text() |
| views/js/lengow/order.js | Adds URL validation before opening links |
| views/js/lengow/main_setting.js | Adds URL validation before redirecting to selected log download |
| views/js/lengow/feed.js | Adds URL validation + replaces .html() with .text() for counters |
| views/css/lengow-pages.css | Updates dashboard/home layout styling |
| views/css/lengow-layout.css | Adds PS9 layout adjustments and stronger link styling |
| views/css/lengow-components.css | Adjusts component styling and link reset |
| views/PrestaShop/Admin/Sell/Order/Order/Blocks/View/shipping.html.twig | Removes overridden PrestaShop order shipping block |
| views/PrestaShop/Admin/Sell/Order/Order/Blocks/View/Modal/update_shipping_modal.html.twig | Removes overridden PrestaShop shipping modal |
| tools/translate.php | Adds types and PHPDoc for CSV writer |
| tools/checkmd5.php | Adds types and PHPDoc, and typed CSV writer |
| tools/build.sh | Adjusts build cleanup list ordering/comment |
| tests/phpstan/index.php | Adds index hardening file for phpstan test dir |
| tests/index.php | Adds index hardening file for tests dir |
| src/Service/index.php | Adds index hardening file for service dir |
| src/Service/OrderRefundDataUpdater.php | Introduces service to persist refund reason/mode |
| src/Controller/Admin/LengowToolboxAdminController.php | Adds Symfony admin controller for Toolbox |
| src/Controller/Admin/LengowOrderSettingAdminController.php | Adds Symfony admin controller for Order Settings |
| src/Controller/Admin/LengowOrderAdminController.php | Adds Symfony admin controller for Orders |
| src/Controller/Admin/LengowMainSettingAdminController.php | Adds Symfony admin controller for Main Settings |
| src/Controller/Admin/LengowLegalsAdminController.php | Adds Symfony admin controller for Legals |
| src/Controller/Admin/LengowHomeAdminController.php | Adds Symfony admin controller for Home |
| src/Controller/Admin/LengowHelpAdminController.php | Adds Symfony admin controller for Help |
| src/Controller/Admin/LengowFeedAdminController.php | Adds Symfony admin controller for Feed |
| src/Controller/Admin/LengowDashboardAdminController.php | Adds Symfony admin controller for Dashboard |
| src/Controller/Admin/AbstractLengowAdminController.php | Adds shared Symfony admin base controller bridging legacy controllers |
| phpstan.neon | Adds PHPStan config (level 6) and ignore rules |
| it.php | Updates Italian translation string key/content |
| fr.php | Updates French translation string key/content + fixes grammar/accents |
| es.php | Updates Spanish translation string key/content |
| en.php | Replaces incorrect PHP class content with translations array |
| controllers/front/toolbox.php | Adds toolbox FrontController replacing webservice endpoint |
| controllers/front/index.php | Adds index hardening file for controllers/front |
| controllers/front/cron.php | Adds cron FrontController replacing webservice endpoint |
| controllers/admin/AdminLengowToolboxController.php | Removes legacy ModuleAdminController wrapper |
| controllers/admin/AdminLengowOrderSettingController.php | Removes legacy ModuleAdminController wrapper |
| controllers/admin/AdminLengowOrderController.php | Removes legacy ModuleAdminController wrapper |
| controllers/admin/AdminLengowMainSettingController.php | Removes legacy ModuleAdminController wrapper |
| controllers/admin/AdminLengowHomeController.php | Removes legacy ModuleAdminController wrapper |
| controllers/admin/AdminLengowHelpController.php | Removes legacy ModuleAdminController wrapper |
| controllers/admin/AdminLengowDashboardController.php | Removes legacy ModuleAdminController wrapper |
| config/services.yml | Imports admin DI service definitions |
| config/routes.yml | Replaces old admin override routes with PS9 Symfony routes for module pages |
| config/admin/services.yml | Registers admin controllers + OrderRefundDataUpdater in DI container |
| composer.json | Requires PHP >=8.1 and adds PSR-4 mapping for Symfony controllers |
| classes/models/LengowTranslation.php | Adds typing and path safety for translation file loading |
| classes/models/LengowToolboxElement.php | Adds typing and escapes toolbox links |
| classes/models/LengowShop.php | Adds typing for shop lookup helpers |
| classes/models/LengowOrderLine.php | Adds typing and method signatures |
| classes/models/LengowOrderError.php | Adds typing and tighter signatures |
| classes/models/LengowOrderDetail.php | Refactors return carrier/tracking persistence to DB updates + typing |
| classes/models/LengowOrderCarrier.php | Adds typed properties and typed constructor |
| classes/models/LengowNameParser.php | Adds typing and path allowlist checks |
| classes/models/LengowMethod.php | Adds typing and replaces Tools::strlen with mb_strlen |
| classes/models/LengowLog.php | Adds typing, path allowlist, and safer download filename |
| classes/models/LengowLink.php | Adds typing to admin link helper |
| classes/models/LengowGender.php | Adds typing and fixes precedence in returned gender ID |
| classes/models/LengowFile.php | Adds typed properties/methods and path allowlist checks |
| classes/models/LengowFeed.php | Adds typing and switches context access to LengowContext |
| classes/models/LengowCustomer.php | Adds typing, hardens field assignment, and simplifies size validation |
| classes/models/LengowCountry.php | Adds typing and switches context access to LengowContext |
| classes/models/LengowContext.php | Adds centralized Context provider (bridge for PS9 deprecation) |
| classes/models/LengowConfigurationForm.php | Adds typing and escapes rendered HTML inputs |
| classes/models/LengowCatalog.php | Adds typing and tightens token casting |
| classes/models/LengowBackup.php | Adds typing and path allowlist check |
| classes/controllers/LengowToolboxController.php | Ports Smarty assigns to controller templateVars |
| classes/controllers/LengowOrderSettingController.php | Switches AJAX partial rendering to Twig + JSON helpers |
| classes/controllers/LengowMainSettingController.php | Ports Smarty assigns to controller templateVars |
| classes/controllers/LengowHomeController.php | Switches AJAX partial rendering to Twig + JSON helpers |
| classes/controllers/LengowFeedController.php | Switches JSON outputs to helper + templateVars on full page |
| classes/controllers/LengowDashboardController.php | Switches JSON outputs to helper + templateVars on full page |
| .php-cs-fixer.dist.php | Adds PHP-CS-Fixer configuration |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <br/> | ||
| <p> | ||
| {{ locale.t('connection.home.no_account') }} | ||
| <a href="https://my.{{ lengowUrl }}" target="_blank"> |
There was a problem hiding this comment.
External links opened with target="_blank" should include rel="noopener noreferrer" to prevent reverse-tabnabbing and to match common security guidance. Add rel="noopener noreferrer" on this and similar external links (support/help center, my.lengow) across the Twig templates.
| <a href="https://my.{{ lengowUrl }}" target="_blank"> | |
| <a href="https://my.{{ lengowUrl }}" target="_blank" rel="noopener noreferrer"> |
| <a href="#" class="lgw-modal-delete"> | ||
| <button type="button" data-toggle="modal" data-target="#openDeleteModal" | ||
| class="lgw-btn lgw-btn-red lengow_delete_module" name="delete_module"> | ||
| {{ locale.t('global_setting.screen.button_i_want_uninstall') }} | ||
| </button> | ||
| </a> | ||
| <div class="lgw-modal"> | ||
| <a href="#" class="modal-close js-close-this-modal"></a> | ||
| <div class="lgw-modal-inner"> | ||
| <div class="scrollable no-margin"> | ||
| <div class="scrollable-in"> | ||
| <div class="lgw-content-section text-center"> | ||
| <img src="{{ lengowPathUri }}views/img/laser-gun.png"> |
There was a problem hiding this comment.
This markup nests a <button> inside an <a>, which is invalid HTML and can cause inconsistent click/keyboard behavior for assistive tech and browsers. Replace with a single interactive element (either a <button> styled as a link or an <a role="button">), and add an alt attribute to the image for accessibility.
| <a href="#" class="lgw-modal-delete"> | |
| <button type="button" data-toggle="modal" data-target="#openDeleteModal" | |
| class="lgw-btn lgw-btn-red lengow_delete_module" name="delete_module"> | |
| {{ locale.t('global_setting.screen.button_i_want_uninstall') }} | |
| </button> | |
| </a> | |
| <div class="lgw-modal"> | |
| <a href="#" class="modal-close js-close-this-modal"></a> | |
| <div class="lgw-modal-inner"> | |
| <div class="scrollable no-margin"> | |
| <div class="scrollable-in"> | |
| <div class="lgw-content-section text-center"> | |
| <img src="{{ lengowPathUri }}views/img/laser-gun.png"> | |
| <button type="button" data-toggle="modal" data-target="#openDeleteModal" | |
| class="lgw-btn lgw-btn-red lengow_delete_module lgw-modal-delete" name="delete_module"> | |
| {{ locale.t('global_setting.screen.button_i_want_uninstall') }} | |
| </button> | |
| <div class="lgw-modal"> | |
| <a href="#" class="modal-close js-close-this-modal"></a> | |
| <div class="lgw-modal-inner"> | |
| <div class="scrollable no-margin"> | |
| <div class="scrollable-in"> | |
| <div class="lgw-content-section text-center"> | |
| <img src="{{ lengowPathUri }}views/img/laser-gun.png" alt="{{ locale.t('global_setting.screen.title_modal_uninstall') }}"> |
| <a href="#" class="lgw-modal-delete"> | ||
| <button type="button" data-toggle="modal" data-target="#openDeleteModal" | ||
| class="lgw-btn lgw-btn-red lengow_delete_module" name="delete_module"> | ||
| {{ locale.t('global_setting.screen.button_i_want_uninstall') }} | ||
| </button> | ||
| </a> | ||
| <div class="lgw-modal"> | ||
| <a href="#" class="modal-close js-close-this-modal"></a> | ||
| <div class="lgw-modal-inner"> | ||
| <div class="scrollable no-margin"> | ||
| <div class="scrollable-in"> | ||
| <div class="lgw-content-section text-center"> | ||
| <img src="{{ lengowPathUri }}views/img/laser-gun.png"> |
There was a problem hiding this comment.
This markup nests a <button> inside an <a>, which is invalid HTML and can cause inconsistent click/keyboard behavior for assistive tech and browsers. Replace with a single interactive element (either a <button> styled as a link or an <a role="button">), and add an alt attribute to the image for accessibility.
| <a href="#" class="lgw-modal-delete"> | |
| <button type="button" data-toggle="modal" data-target="#openDeleteModal" | |
| class="lgw-btn lgw-btn-red lengow_delete_module" name="delete_module"> | |
| {{ locale.t('global_setting.screen.button_i_want_uninstall') }} | |
| </button> | |
| </a> | |
| <div class="lgw-modal"> | |
| <a href="#" class="modal-close js-close-this-modal"></a> | |
| <div class="lgw-modal-inner"> | |
| <div class="scrollable no-margin"> | |
| <div class="scrollable-in"> | |
| <div class="lgw-content-section text-center"> | |
| <img src="{{ lengowPathUri }}views/img/laser-gun.png"> | |
| <button type="button" data-toggle="modal" data-target="#openDeleteModal" | |
| class="lgw-btn lgw-btn-red lengow_delete_module lgw-modal-delete" name="delete_module"> | |
| {{ locale.t('global_setting.screen.button_i_want_uninstall') }} | |
| </button> | |
| <div class="lgw-modal"> | |
| <a href="#" class="modal-close js-close-this-modal"></a> | |
| <div class="lgw-modal-inner"> | |
| <a href="#" class="modal-close js-close-this-modal"></a> | |
| <div class="lgw-modal-inner"> | |
| <div class="scrollable no-margin"> | |
| <div class="scrollable-in"> | |
| <div class="lgw-content-section text-center"> | |
| <img src="{{ lengowPathUri }}views/img/laser-gun.png" alt="{{ locale.t('global_setting.screen.title_modal_uninstall') }}"> |
| <input type="hidden" name="action" value="process"> | ||
| <div class="lgw-box"> | ||
| <h2>{{ locale.t('global_setting.screen.notification_alert_title') }}</h2> | ||
| {{ mail_report|raw }} |
There was a problem hiding this comment.
These variables are rendered with |raw, which disables Twig auto-escaping and can introduce XSS if any of the content is user-influenced (directly or indirectly). If these strings are meant to contain HTML, ensure they are generated exclusively from trusted server-side templates/whitelisted markup; otherwise, remove |raw and output escaped content (or rebuild these blocks using Twig templates/components rather than raw HTML strings).
| {{ mail_report|raw }} | |
| {{ mail_report }} |
| <div class="lgw-box"> | ||
| <h2>{{ locale.t('global_setting.screen.default_export_carrier_title') }}</h2> | ||
| <p>{{ locale.t('global_setting.screen.default_export_carrier_description') }}</p> | ||
| {{ defaultExportCarrier|raw }} |
There was a problem hiding this comment.
These variables are rendered with |raw, which disables Twig auto-escaping and can introduce XSS if any of the content is user-influenced (directly or indirectly). If these strings are meant to contain HTML, ensure they are generated exclusively from trusted server-side templates/whitelisted markup; otherwise, remove |raw and output escaped content (or rebuild these blocks using Twig templates/components rather than raw HTML strings).
| {{ defaultExportCarrier|raw }} | |
| {{ defaultExportCarrier }} |
| <p>{{ locale.t('global_setting.screen.debug_mode_description') }}</p> | ||
| {{ debug_report|raw }} | ||
| <div id="lengow_wrapper_debug" style="display:none;"> | ||
| {{ debug_wrapper|raw }} |
There was a problem hiding this comment.
These variables are rendered with |raw, which disables Twig auto-escaping and can introduce XSS if any of the content is user-influenced (directly or indirectly). If these strings are meant to contain HTML, ensure they are generated exclusively from trusted server-side templates/whitelisted markup; otherwise, remove |raw and output escaped content (or rebuild these blocks using Twig templates/components rather than raw HTML strings).
| {{ debug_wrapper|raw }} | |
| {{ debug_wrapper }} |
| function lengowIsValidUrl(url) { | ||
| try { | ||
| var parsed = new URL(url, window.location.origin); | ||
| return parsed.protocol === 'http:' || parsed.protocol === 'https:'; | ||
| } catch (e) { | ||
| return false; | ||
| } | ||
| } |
There was a problem hiding this comment.
lengowIsValidUrl() is duplicated across multiple admin JS files (order.js, feed.js, main_setting.js). Consider centralizing it into a shared module/global utility (e.g., views/js/lengow/admin.js) to avoid divergent behavior over time and simplify future security fixes.
| function lengowIsValidUrl(url) { | |
| try { | |
| var parsed = new URL(url, window.location.origin); | |
| return parsed.protocol === 'http:' || parsed.protocol === 'https:'; | |
| } catch (e) { | |
| return false; | |
| } | |
| } | |
| // Use a shared/global URL validation helper if available, otherwise define it once here. | |
| if (typeof window.lengowIsValidUrl !== 'function') { | |
| window.lengowIsValidUrl = function (url) { | |
| try { | |
| var parsed = new URL(url, window.location.origin); | |
| return parsed.protocol === 'http:' || parsed.protocol === 'https:'; | |
| } catch (e) { | |
| return false; | |
| } | |
| }; | |
| } | |
| var lengowIsValidUrl = window.lengowIsValidUrl; |
| right: -16px; | ||
| } | ||
|
|
||
| .lgw-ps9-content:has(.lengow-nav-bottom) .cms-global { |
There was a problem hiding this comment.
The :has() selector still has uneven browser support depending on the embedded admin browser/WebView. If PrestaShop back-office needs to work in environments without :has(), this rule will be ignored and layout can regress. Add a non-:has() fallback (e.g., an extra wrapper class toggled server-side) so spacing doesn’t rely solely on :has().
| .lgw-ps9-content:has(.lengow-nav-bottom) .cms-global { | |
| .lgw-ps9-content:has(.lengow-nav-bottom) .cms-global, | |
| .lgw-ps9-content.lgw-ps9-content--has-nav-bottom .cms-global { |
| * - Symfony controllers call setContext() via the @required setter injection in | ||
| * AbstractLengowAdminController, ensuring the context is always wired on PS9. |
There was a problem hiding this comment.
The comment mentions “@required setter injection” in AbstractLengowAdminController, but the current implementation sets the context in the controller constructor. Update the docblock to reflect the actual wiring mechanism to avoid misleading future maintainers.
| * - Symfony controllers call setContext() via the @required setter injection in | |
| * AbstractLengowAdminController, ensuring the context is always wired on PS9. | |
| * - Symfony controllers rely on AbstractLengowAdminController, which sets the | |
| * context in its constructor to ensure the context is always wired on PS9. |
| private static function getIdOrderCarrier(int $orderId): int | ||
| { | ||
| $result = Db::getInstance()->getValue( | ||
| 'SELECT id_order_carrier FROM ' . _DB_PREFIX_ . 'order_carrier WHERE id_order = ' . $orderId . ' ORDER BY id_order_carrier DESC' |
There was a problem hiding this comment.
This query uses ORDER BY ... DESC but no LIMIT 1. Since only a single value is needed, add LIMIT 1 to reduce unnecessary work and make intent explicit (especially if an order has multiple carriers).
| 'SELECT id_order_carrier FROM ' . _DB_PREFIX_ . 'order_carrier WHERE id_order = ' . $orderId . ' ORDER BY id_order_carrier DESC' | |
| 'SELECT id_order_carrier FROM ' . _DB_PREFIX_ . 'order_carrier WHERE id_order = ' . $orderId . ' ORDER BY id_order_carrier DESC LIMIT 1' |
⚠ BREAKING CHANGES
_PS_VERSION_ < 1.7/< 1.5/< 1.6have been removed.Features
Admin Controllers — full migration to Symfony (PS 9 routing)
AbstractLengowAdminControllerbase class, located insrc/Controller/Admin/.route_name(lengow_home,lengow_dashboard, …) that is registered with the PS 9 router on install. On PS 8 the legacyAdminLengow*controller names are used as before — the install logic selects the right approach based on the PS version.getContent()now uses the Symfonyrouterservice to redirect tolengow_homeinstead of the oldLengowLinkhelper. AclearCompiledCache()helper deletes stale routing and DI-container cache files on install/uninstall so new routes are picked up immediately.controllers/admin/directory and the singlesrc/Controller/AdminOrderController.phphave been removed; all logic lives in the newsrc/Controller/Admin/hierarchy.controllers/admin/AdminOrdersController.php) has been removed; order-page customisation is now done exclusively through hooks.Front Controllers replacing the
webservice/directorywebservice/export.php,webservice/cron.phpandwebservice/toolbox.phpno longer exist as physical files. Three new FrontControllers (controllers/front/export.php,cron.php,toolbox.php) replace them.hookModuleRoutes()implementation maps the old URLs (modules/lengow/webservice/*.php) to these controllers, preserving full backward-URL compatibility so existing cron jobs and integrations do not break.Order detail — new Lengow tab
displayAdminOrderTabLinkanddisplayAdminOrderTabContent, inject a dedicated Lengow tab into the native PS order detail page.src/Service/OrderRefundDataUpdater.phpservice handles saving refund data from the tab form.New
LengowContextclassclasses/models/LengowContext.phpintroduced as a thin wrapper aroundContext::getContext()that is being deprecated in the next prestashop updates. All code that previously calledContext::getContext()directly has been migrated toLengowContext::getContext(), making the context easier to mock and consistent across the codebase.New PHP 8.1 Enums (
src/Enum/)src/Enum/for type-safe representation of domain constants (previously raw strings or class constants).Symfony service container integration
config/services.ymlandconfig/admin/routing files added so module controllers and services are registered in the PS Symfony DI container.Changes
Tracker removed
hookDisplayHome,hookPaymentTop,hookFooter,hookDisplayFooter, page-type constantsLENGOW_TRACK_*, static fields$currentPageType,$idCart,$idOrder,$orderPayment, etc.) has been fully removed fromLengowHook. ThedisplayFooterhook is no longer registered.Hook fixes and additions
paymentTophook registration corrected todisplayPaymentTopto match thehookDisplayPaymentTop()method inlengow.php.actionProductCancelhook added (PS 8.0+) to handle partial order cancellations.displayAdminOrderTabLinkanddisplayAdminOrderTabContenthooks registered (PS 1.7+).moduleRouteshook registered (PS 1.5+) to expose the front-controller URL mappings.homehook unregistered on upgrade; replaced bydisplayHome(PS 8.0+).Views — Smarty
.tpl→ Twig.html.twig.tpl) to Twig (.html.twig). Affected pages: Dashboard, Feed, Help, Home (connection flow), Order, Order Settings, Main Settings, Legals, Toolbox.layout.tpl,header.tpl,footer.tpl,header_order.tpl) removed.views/PrestaShop/Admin/Sell/Order/…) removed; order display is now handled via the new tab hooks.Strict PHP type declarations across the entire codebase
LengowHook,LengowInstall,LengowMain,LengowImport,LengowConnector,LengowSync,LengowConfiguration, and all remaining model classes now carry explicit parameter types, typed properties, and return types (including union types likeint|false,array|false,mixed).Constructor signatures tightened
LengowHook,LengowInstallconstructors now accept an explicitContext $contextargument instead of callingContext::getContext()internally. Injected fromlengow.php.Bug Fixes
.attr('href')orwindow.locationto build redirect URLs now validate targets through alengowIsValidUrl()helper that checks protocol (http:/https:) before following any link. Affectsorder.js,feed.js,main_setting.js,order_setting.jsand the corresponding CSS files that loaded affected scripts.LengowImport: Fixed a missingreturnstatement that caused the import loop to exit prematurely under certain conditions.LengowInstall:setInstallationStatus(false)is now called before runningupdate()during module upgrade to prevent a staletruestatus from skipping install steps.hookActionObjectUpdateAfter: Removed a redundantinstanceof Ordercheck —LengowOrder::isFromLengow()already validates the object type internally.hookActionProductCancel: Replaced$lengowOrder instanceof LengowOrderguard withValidate::isLoadedObject($orderDetail)for consistency with PS conventions.<title>tags corrected via the YML translation pipeline.Removed
webservice/directory (replaced by front controllers, see above).controllers/admin/directory (replaced bysrc/Controller/Admin/, see above).src/Controller/AdminOrderController.php(merged into new hierarchy).views/PrestaShop/…).LengowMain::WEBSERVICE_EXPORT,WEBSERVICE_CRON,WEBSERVICE_TOOLBOXconstants.